package akbderby.page;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.slim3.controller.Navigation;
import org.slim3.datastore.Datastore;
import org.slim3.util.BeanUtil;

import scenic3.annotation.ActionPath;
import scenic3.annotation.Default;
import scenic3.annotation.Page;
import scenic3.annotation.Var;
import akbderby.model.Blobstore;
import akbderby.model.BlobstoreCondition;
import akbderby.model.UploadedData;
import akbderby.service.InfoService;
import akbderby.service.UploadService;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@Page("/info")
public class InfoPage extends BasePage {

    private UploadService uploadService = new UploadService();
    private InfoService infoService = new InfoService();

    @ActionPath("ranking/{limit}")
    public Navigation ranking(@Var("limit") int limit) {
        if (limit < 1)
            limit = 10;

        List<Blobstore> rankingList = Datastore.query(Blobstore.class).asList();
        Collections.sort(rankingList, new CountComparator());
        rankingList = getLimitedList(rankingList, limit - 1);

        int rank = 1;
        int count = 0;
        boolean first = true;
        for (Blobstore blobstore : rankingList) {
            if (!first && count != blobstore.getCount()) {
                rank++;
            }
            first = false;
            blobstore.setRank(rank);
            count = blobstore.getCount();
        }

        requestScope("totalRanking", rankingList);
        return forward("/info/ranking.jsp");
    }

    @ActionPath("search")
    public Navigation search() {
        BlobstoreCondition condition = new BlobstoreCondition();
        BeanUtil.copy(request, condition);
        requestScope("resultList", infoService.getSelect(condition));
        return forward("/info/search.jsp");
    }

    @ActionPath("profile/{id}")
    public Navigation profile(@Var("id") String id) {
        Key key = KeyFactory.stringToKey(id);
        Blobstore blobstore = Datastore.get(Blobstore.class, key);

        requestScope("profile", blobstore);
        return forward("/info/profile.jsp");
    }

    @ActionPath("show/{id}")
    public Navigation show(@Var("id") String id) throws Exception {
        Key key = KeyFactory.stringToKey(id);
        Blobstore blobstore = Datastore.get(Blobstore.class, key);
        UploadedData data =
            uploadService.getData(
                blobstore.getImageKey(),
                blobstore.getImageVersion());
        byte[] bytes = uploadService.getBytes(data);
        show(data.getFileName(), bytes);
        return null;
    }

    @Default
    public Navigation index() {
        return redirect("ranking/10");
    }

    private List<Blobstore> getLimitedList(List<Blobstore> list, int limit) {
        List<Blobstore> returnList = new ArrayList<Blobstore>(list.size());
        int size = 0;
        for (Blobstore object : list) {
            if (limit > 0 && size > limit)
                break;
            returnList.add(object);
            size++;
        }
        return returnList;
    }

    private class PointComparator implements Comparator<Blobstore> {
        public int compare(Blobstore o1, Blobstore o2) {
            int o1Point = o1.getPoint();
            int o2Point = o2.getPoint();
            if (o1Point > o2Point)
                return -1;
            if (o1Point < o2Point)
                return 1;

            int o1Count = o1.getCount();
            int o2Count = o2.getCount();
            if (o1Count > o2Count)
                return -1;
            if (o1Count < o2Count)
                return 1;
            return 0;
        }
    }

    private class CountComparator implements Comparator<Blobstore> {
        public int compare(Blobstore o1, Blobstore o2) {
            int o1Count = o1.getCount();
            int o2Count = o2.getCount();
            if (o1Count > o2Count)
                return -1;
            if (o1Count < o2Count)
                return 1;
            return 0;
        }
    }
}
